package frame.project;

import java.util.ArrayList;
import java.util.Random;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;

public class AlbumCustom extends Activity{
	// Pre defined set of array
	// List complete name of the xml
	int[] xmlId= {R.layout.album_type_1,R.layout.album_type_2, R.layout.album_type_3};
	
	// Lists every item id inside each xml
	int[] xmlPic1 = {R.id.custom1pic1, R.id.custom1pic2, R.id.custom1pic3};
	int[] xmlPic2 = {R.id.custom2pic1, R.id.custom2pic2};
	int[] xmlPic3 = {R.id.custom3pic1, R.id.custom3pic2, R.id.custom3pic3};
	
	int[] xmlText1 = {R.id.custom1text11, R.id.custom1text12, 
					R.id.custom1text21, R.id.custom1text22,
					R.id.custom1text31, R.id.custom1text32};
	int[] xmlText2 = {R.id.custom2text11, R.id.custom2text12,
					R.id.custom2text21, R.id.custom2text22};
	int[] xmlText3 = {R.id.custom3text11, R.id.custom3text12, 
					R.id.custom3text21, R.id.custom3text22,
					R.id.custom3text31, R.id.custom3text32};

	
	// Collection of colors name, for updating database
	String[] color = {"Red", "Orange", "Yellow", "Green", "Blue", "Pink", "Purple", "Neutral"};
	
	// Lists styles that existed
	int[][] xmlPic = {xmlPic1, xmlPic2, xmlPic3};
	int[][] xmlText = {xmlText1, xmlText2, xmlText3};
	
	// Array of button colors' IDs, used for listener
	int[] btnColor = {R.id.btnRed, R.id.btnOrange, R.id.btnYellow, R.id.btnGreen, R.id.btnBlue, R.id.btnPink, R.id.btnPurple, R.id.btnNeutral};
	
	// Lists how many style exists
	int numOfStyle = xmlId.length;
	
	// Array list used to hold style numbers, so that we will not have to random style everytime user swipes
	ArrayList<Integer> styleList = new ArrayList<Integer>();
	
	// ArrayList used to hold the images path
	// Paths are ordered based on their randomized xml.
	// xml 1 - path 1,2,3; xml 2 - path 4,5; etc.
	//ArrayList<ArrayList<String>> imageList = new ArrayList<ArrayList<String>>();
	
	// Array list used to hold image path
	ArrayList<ArrayList<String>> imgUriList = new ArrayList<ArrayList<String>>();
	
	// Array list used to hold buttons for listeners' use
	ArrayList<Button> btnList = new ArrayList<Button>();
	
	// Determines which index of image to be printed 
	int curImagePos = 0;
	
	// Helps to keep track of the previous position. To determine if user swipes left or right
	int prevPos; 
	
	View view;
	ImageView imgEnlarge, imgThumbs;
	TextView text1, text2;
	String colorIndex;	
	Button btn;
	Bitmap bm;
	ImageAdapter imageAdapter = new ImageAdapter();
	ImagePager pagerAdapter;
	Dialog imgDialog;
	ProgressDialog progress;
	ViewPager customPager, pager;
	Context context;
	Cursor c;
	DBAdapter db = new DBAdapter(this);
	ImageProduce image = new ImageProduce();
	LayoutInflater inflater;
	
	/**
	 * ImageAdapter class used to swipe right or left to browse filmstrip photos
	 * @author Marcel
	 *
	 */
	public class ImageAdapter extends PagerAdapter{
		public Object instantiateItem(View collection, int position) {
			
			//bm.recycle();
			
			// Sets .xml file as the view in the ViewPager
            inflater = (LayoutInflater) collection.getContext()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(xmlId[styleList.get(position)], null);
            ((ViewPager) collection).addView(view, 0);
            
            // Calls a method to set picture inside the xml
            setView(position);
            
            System.gc();
            //bm.recycle();
            
            return view;
		}

		@Override
		public int getCount() {
			return styleList.size();
		}
		
		@Override
	    public void destroyItem(ViewGroup collection, int position, Object o) {
			Log.d("DESTROY", "destroying view at position " + position);
		    collection.removeView((View) o);
		    System.gc();
	    }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            return arg0 == ((View) arg1);
        }
        @Override
        public Parcelable saveState() {
            return null;
        }
	}
	
	/**
     * Adapter class for ViewPager
     * Displays next and previous pictures by swiping right n left
     * @author Marcel
     *
     */
	public class ImagePager extends PagerAdapter{
		@Override
		public int getCount() {
			return imgUriList.size();
		}
	
		@Override
		public boolean isViewFromObject(View view, Object object) {
			return view == ((ImageView) object);
		}
		
		 @Override
		 // Displays picture
		 public Object instantiateItem(ViewGroup container, int position) {
			 
			 if (bm != null){
				 bm = null;
				 imgEnlarge = null;
			 }
		     imgEnlarge = new ImageView(AlbumCustom.this);
		     imgEnlarge.setScaleType(ImageView.ScaleType.FIT_CENTER);
		     imgEnlarge.setAdjustViewBounds(true);
		     
		     // Gets the image from the path
		     bm = image.decodeBitmap(imgUriList.get(position).get(0), 300 , 300);
		     
		     int id = Integer.parseInt(imgUriList.get(position).get(1));
		     imgEnlarge.setImageBitmap(bm);
		     imgEnlarge.setOnLongClickListener(new ListenerImageLong(id));
		     ((ViewPager) container).addView(imgEnlarge, 0);
		     System.gc();
		     return imgEnlarge;
		 }
	
		 @Override
		 public void destroyItem(ViewGroup collection, int position, Object o) {
			 Log.d("DESTROY", "destroying view at position " + position);
			 collection.removeView((View) o);
			 System.gc();
		 }

	}

	/**
	 * Listener for image description when clicked 
	 * Display a pop up to set description
	 * @author Marcel
	 *
	 */
	public class ListenerDescriptionClick implements OnClickListener{
		TextView text;
		int position;
		
		public ListenerDescriptionClick(TextView tv, int position){
			this.text = tv;
			this.position = position;
		}
		
		public void onClick(View v) {
			dialogDescription(text,text.getText().toString(), position);
		}
	}
	
	/**
	 * Listener class for clear button in description dialog
	 * Clears up the input box 
	 * @author Marcel
	 *
	 */
	public class ListenerDescriptionClear implements View.OnClickListener{
		EditText input;
		
		public ListenerDescriptionClear(EditText in){
			this.input = in;
		}
		
		public void onClick(View v) {
			input.setText("");
		}
		
	}
	
	/**
	 * Listener class for Ok button in description dialog 
	 * Updates image's description in database and gallery
	 * @author Marcel
	 *
	 */
	public class ListenerDescriptionOk implements View.OnClickListener{
		TextView tv;
		EditText input;
		int position;
		Dialog dialog;
		
		public ListenerDescriptionOk(TextView tvVar, EditText input, int position, Dialog dialog){
			this.tv = tvVar;
			this.input = input;
			this.position = position;
			this.dialog = dialog;
		}
		
		public void onClick(View v) {
			Cursor c = db.getPath();
			c.moveToPosition(position);
			String text = input.getText().toString();
			db.updatePath(c.getString(1).toString(), c.getString(2), c.getString(3).toString(), text, c.getInt(5));
			
			tv.setText(text);
			dialog.cancel();
		}
		
	}
		
	/**
	 * Listener class for image when clicked
	 * Display a pop up window to show the image in a larger size
	 * @author Marcel
	 *
	 */
	public class ListenerImageClick implements OnClickListener{
		int position = 0;
		
		public ListenerImageClick(int pos){
			this.position = pos;
		}
		
		public void onClick(View v) {
			dialogImage(position);
		}
		  
	  }
	
	/**
	 * Listener class for image when it is long-clicked
	 * Displays a pop up to set label for an image
	 * @author Marcel
	 *
	 */
	public class ListenerImageLong implements OnLongClickListener{
		int position;
		
		public ListenerImageLong(int pos){
			this.position = pos;
		}
		
		public boolean onLongClick(View arg0) {
			dialogLabel(position);
			return false;
		}
		
	}

	/**
	 * Listener class for Ok button in the label setting dialog
	 * Updates database in Color column
	 * @author Marcel
	 *
	 */
	public class ListenerLabelOk implements View.OnClickListener{
		int index, picPos;
		Dialog dialog;
		
		public ListenerLabelOk(int x, Dialog dialog){
			this.picPos = x;
			this.dialog = dialog;
		}
		
		public void onClick(View v) {
			// Checks which button is currently disabled, indicates the index of label user wants to set
			for (int x = 0; x < btnList.size(); x++){
				if (btnList.get(x).isEnabled() == false){
					index = x;
					break;
				}
			}
			
			Cursor c = db.getPath();
			c.moveToPosition(picPos);
			
			// Update image's label color
			db.updatePath(c.getString(1), c.getString(2), color[index], c.getString(4), c.getInt(5));
			
			// Cancels the dialog
			dialog.cancel();
		}
		
	}

	/**
	 * Custom listener for label button
	 * Stores the button in the object
	 * Disables the clicked button, and enables all the other buttons
	 * @author Marcel
	 *
	 */
	public class ListenerLabelBtn implements View.OnClickListener{
		int pos;
		Button button;
		
		public ListenerLabelBtn(int x){
			this.pos = x;
		}
	
		public void onClick(View v) {
			for (int x = 0; x < btnList.size(); x++){
				if (x != pos){
					// Enable the other 7 buttons
					btnList.get(x).setEnabled(true);
					
				}else{
					
					// Disable the pressed button
					btnList.get(x).setEnabled(false);
				}
			}
		}
	}
	
	/**
	 * Background process to load images and set image to their ImageView
	 * @author Marcel
	 *
	 */
	class LoadImages extends AsyncTask<Object, Bitmap , Object> {
		int position;
		ImageView img;
		
		/**
		 * Thread constructor
		 * @param position - position of the image in ArrayList
		 * @param img - ImageView used for the image
		 */
		public LoadImages(int position, ImageView img){
			this.position = position;
			this.img = img;
		}
		
	    protected Object doInBackground(Object... params) {
	    	try{
	    		if (bm != null){
	    			bm = null;
	    		}

	    		// Decode bitmap
	    		bm = image.decodeBitmap(imgUriList.get(position).get(0), 200, 200);
	    		
	    		// Calls onProgressUpdate
	    		publishProgress(bm);
	    		
	    	}catch(Exception e){
	    		Log.d(getLocalClassName(), "File not found");
	    	}
	    	return null;
	    }
	  
	    @Override
	    public void onProgressUpdate(Bitmap... value) {
	    	try{
	    		// Set bitmap fetched from SDCard to ImageView
	    		img.setImageBitmap(value[value.length - 1]);
	    	}catch(Exception e){
	    		Log.d(getLocalClassName(), "File not found");
	    	}
	    	
	    }
	   
	    @Override
	    protected void onPostExecute(Object result) {
	    	System.gc();
	    }
	}

	/**
	 * Background process to load image's name and image's description
	 * @author Marcel
	 *
	 */
	class LoadTexts extends AsyncTask<Object, String , Object> {
		int id;
		TextView tvDesc, tvName;
		String desc, name;
		
		/**
		 * Thread constructor
		 * @param id - image's id in database
		 * @param tvName - TextView used for image's name
		 * @param tvDesc - TextView used for image's description
		 */
		public LoadTexts(int id, TextView tvName, TextView tvDesc){
			this.id = id;
			this.tvName = tvName;
			this.tvDesc = tvDesc;
		}
		
	    protected Object doInBackground(Object... params) {
	    	c = db.getPath();
	    	c.moveToPosition(id);
	    	
	    	// Retrieve data from database
	    	desc = c.getString(4);
	    	name = getName(c.getString(1).toString());
	    	
	    	// Call on progress update
	    	publishProgress(desc);
	    	return null;
	    }
	  
	    @Override
	    public void onProgressUpdate(String... value) {
	    	// Update TextView
	    	tvName.setText(name);
	    	tvDesc.setText(desc);
	    }
	    
	   
	    @Override
	    protected void onPostExecute(Object result) {
	    	if (progress != null){
	    		progress.dismiss();
	    		progress = null;
	    	}
	    	System.gc();
	    }
	}
	
	/**
	 * 
	 * @author Marcel
	 *
	 */
	class LoadStyles extends AsyncTask<Object, String , Object> {
		@Override
		protected void onPreExecute(){
			progress = ProgressDialog.show(AlbumCustom.this, "", "Loading.. Please Wait..");
		}
		
		@Override
	    protected Object doInBackground(Object... params) {
	    	getPaths();
	    	randomStyle();
	    	return null;
	    }
	  
	    @Override
	    protected void onPostExecute(Object result) {
	    	//progress.dismiss();
	    	System.gc();
	    }
	}
	
	/**
	 * Method used to set pictures into the filmstrip view
	 * @param position - current index of the ViewPager
	 */
	public void setView(int position){
		// Style index that is currently being used
		int index = styleList.get(position);
		
		// Max counter number for loop
		int maxCounter = xmlPic[styleList.get(position)].length;
		
		int text1Id = 0;
		int text2Id = 0;
		
		// Set picture of each ImageView by using each id
		for(int x = 0; x < maxCounter; x++){
			// Retrieves text id
			text1Id = xmlText[index][x*2];
			text2Id = xmlText[index][x*2+1];

			text1 = (TextView) findViewById(text1Id);
			text2 = (TextView) findViewById(text2Id);
			
			text1.setText("");
			text2.setText("");
			
			try{
				if (imgThumbs != null){
					imgThumbs = null;
				}
				imgThumbs = (ImageView) findViewById(xmlPic[index][x]);
				imgThumbs.setScaleType(ScaleType.CENTER_CROP);
				
				// Load images in background process
				new LoadImages(checkPos(position,x), imgThumbs).execute();
				
				// Image's ID in database
				int id = Integer.parseInt(imgUriList.get(checkPos(position,x)).get(1));
				
				// Load text in background process
				new LoadTexts(id, text1, text2).execute();
								
				// Defines the listeners
				imgThumbs.setOnClickListener(new ListenerImageClick(checkPos(position,x)));
				imgThumbs.setLongClickable(true);
				imgThumbs.setOnLongClickListener(new ListenerImageLong(id));
				text2.setOnClickListener(new ListenerDescriptionClick(text2, id));
				
				System.gc();
			}catch(Exception e){
				e.printStackTrace();
			}
			curImagePos++;
		}
	}
	
	/**
	 * Set album title based on album's name
	 */
	public void setTitle(){
		TextView title = (TextView) findViewById(R.id.textTitleCustom);
	    
	    Cursor cur = db.getLabel();
	    
	    for (int x = 0; x < cur.getCount(); x++){
	    	
	    	if (cur.getString(2).toString().equals(colorIndex)){
	    		title.setText(cur.getString(1).toString());
	    	}
	    	
	    	cur.moveToNext();
	    }
	}

	/**
	 * Shows a dialog box to set image description
	 * Sets TextView as well
	 * @param tvDesc
	 */
	public void dialogDescription(TextView tvVar,String strText, int position){
		final TextView tv = tvVar;
		
		final Dialog dialog = new Dialog(this);
		dialog.setContentView(R.layout.dialog);
		dialog.setTitle("Description");
		
		TextView text = (TextView) dialog.findViewById(R.id.dialogText);
		EditText input = (EditText) dialog.findViewById(R.id.dialogInput); 
		Button btnOk = (Button) dialog.findViewById(R.id.dialogOk);
		Button btnClear = (Button) dialog.findViewById(R.id.dialogClear);
		Button btnCancel = (Button) dialog.findViewById(R.id.dialogCancel);
		
		text.setText("Set Description : ");
		input.setText(strText);
		
		btnOk.setOnClickListener(new ListenerDescriptionOk(tv, input, position, dialog));
			
		btnClear.setOnClickListener(new ListenerDescriptionClear(input));
		
		btnCancel.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				dialog.cancel();
			}
		});
		
		dialog.show();
	}

    /**
     * Enlarge image in the album when clicked
     * @param curPos - position of the image clicked
     */
	private void dialogImage(int curPos){
		imgDialog = new Dialog(this);
    	
    	// Request for no title dialog
    	imgDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    	
    	// Set the dialog view
    	imgDialog.setContentView(R.layout.enlargeimage);
    	
    	//initiates ViewPager (for swiping next / previous)
    	pager = (ViewPager) imgDialog.findViewById(R.id.albumPager);
    	pagerAdapter = new ImagePager();
    	pager.setAdapter(pagerAdapter);
    	pager.setCurrentItem(curPos);
    	pager.setOffscreenPageLimit(0);
    
    	imgDialog.setCancelable(true);
    	imgDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
			
			public void onDismiss(DialogInterface dialog) {
				bm.recycle();
				imgEnlarge = null;
			}
		});
    	imgDialog.show();
    }

	/**
	 * Pops up a label setting dialog, if a long-click action is triggered towards an image
	 * @param pos - position of image clicked
	 */
	public void dialogLabel(int pos){
		final Dialog dialog = new Dialog(this);
		
		dialog.setContentView(R.layout.labeldialog);	// Set dialog's view
		dialog.setTitle("Label");	// Set dialog's title
		
		Cursor c = db.getLabel();
		Cursor curPath = db.getPath();
		
		// Go to image's row in database
		curPath.moveToPosition(pos);
		
		// Retrieve's current image's label
		String label = curPath.getString(3).toString();
		
		// Checks the label's index
		int curLabelIndex = 0;
		for (int x = 0; x < btnColor.length; x++){
			if (label.equals(color[x])){
				curLabelIndex = x;
			}
		}
		
		// Defines all the buttons
		for(int x = 0; x < btnColor.length; x++){
			btn = new Button(this);
			btn = (Button) dialog.findViewById(btnColor[x]);
			
			// Adds the button to the arraylist, to be able to be called again later on
			btnList.add(btn);
			
			// Sets on click listener 
			btn.setOnClickListener(new ListenerLabelBtn(x));
			
			// Disabled the button that is labeled with
			// If current label is red, disable red label button
			if (x == curLabelIndex){
				btn.setEnabled(false);
			}
			
			// There are only 7 colors in the database, but here we add 1 more, to un-labeled image called "Neutral" button
			if (x < btnColor.length - 1){
				btn.setText(c.getString(1));
				c.moveToNext();	
			}else{
				btn.setText("Neutral");
			}
		}
		
		
		Button btnOk = (Button) dialog.findViewById(R.id.dialogLabelOk);
		btnOk.setOnClickListener(new ListenerLabelOk(pos, dialog));
						
		Button btnCancel = (Button) dialog.findViewById(R.id.dialogLabelCancel);
		btnCancel.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				dialog.cancel();
			}
		});
	
		// If the dialog is canceled, the arraylist where we store all the buttons is cleared
		dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
			
			public void onCancel(DialogInterface dialog) {
				btnList.clear();
			}
		});
		
		dialog.show();
		
	}

	/**
	 * Randomize xml style and categorizes the pictures with their respectives xml
	 * some xml has 2 and some has 3 pictures inside
	 * @author Marcel
	 * 
	 */
	public void randomStyle(){
		// Current number of pictures that has already been processed
		int curCount = 0;
		
		
		while (true){
			if (imgUriList.size() <= curCount){	// Stops if the number of pictures processed is equal to the list 
				break;
			}
			int rand = new Random().nextInt(numOfStyle);	// Randomized the style
			styleList.add(rand);	// Add the style index to styleList<Integer>
			
			curCount += xmlPic[rand].length;
		}
	}
	
	/**
	 * Checks current image position in the imgUriList, so that we can get the correct index	
	 * @param pos1 - current page
	 * @param pos2 - image index in the page
	 * @return current position
	 */
	public int checkPos(int pos1, int pos2){
		int position = 0;
		for(int a = 0; a < pos1; a++){
			position += xmlPic[styleList.get(a)].length;
		}
		position += pos2;
		return position;
	}
	
	/**
	 * Retrieve file name from picture's path
	 * @param path - picture's path
	 * @return file name
	 */
	public String getName(String path){
		String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
		return name;
	}
		
	/**
	 * Retrieves all paths from database
	 */
	public void  getPaths(){
	        
		Cursor c = db.getPath();
		c.moveToFirst();
	        
		ArrayList<String> list = null;
	        
		for (int x = 0; x < c.getCount(); x++){
			list = new ArrayList<String>();
	        	
			// Retrieves images path from database
			String cursorColor = c.getString(3).toString();
	        	
			// Check if the label equals to the color index label
			if (cursorColor.equals(colorIndex) || colorIndex.equals("Null")){
				list.add(c.getString(1).toString());
				list.add(Integer.toString(x));
	        		
				imgUriList.add(list);
	        }
	        	
			// Move to the next row in database
			c.moveToNext();
       }
	}
	
	/**
	 * Get passed value, to indicate what label to display
	 */
	public void getColorIndex(){
		// Retrieves color index value passed from the previous class, to determines which label to show
        // This value will be hold by this class
        colorIndex = "";
        try{
        	Bundle extras = getIntent().getExtras();
        	
        	// Gets the color index string, for example "Red"
	    	colorIndex = extras.getString("color").toString();
	    	
        }catch(Exception e){
        	
        	// If the previous class didn't pass anything, then it will be assigned as "Null"
        	colorIndex = "Null";
        }
	}
	
	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.layout.menu, menu);
        return true;
    }
	
	 @Override
	    public void onDestroy(){
	    	super.onDestroy();
	    	
	    	// Cleans up everything to reduce memory
	    	db.close();
	    	bm = null;
	    	imgThumbs = null;
	    	imgEnlarge = null;
	    	imgUriList.clear();
	    	System.gc();
	}
	 
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.albumcustom);
        
        db.open();
        
        getColorIndex();
        
        //getPaths();
        
        //randomStyle();
        new LoadStyles().execute();
        
        customPager = (ViewPager) findViewById(R.id.albumCustomPager);
        ImageAdapter adapter = new ImageAdapter();
        customPager.setAdapter(adapter);
        customPager.setCurrentItem(0);
        customPager.setOffscreenPageLimit(0);
        
        Button btnSetting = (Button) findViewById(R.id.btnCustomSetting);
        btnSetting.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				Intent i = new Intent(getApplicationContext(),AlbumGrid.class);
				
				// Pass colorIndex value to AlbumGrid class, so that AlbumGrid also will display the same thing
				Bundle bundle = new Bundle();
				bundle.putString("color", colorIndex);
				i.putExtras(bundle);
				
				startActivity(i);
				finish();
			}
		});
        
        Button btnBack = (Button) findViewById(R.id.btnCustomBack);
        btnBack.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				finish();
			}
		});
        
        setTitle();        
	}
}
